"""
基于能力的路由策略

根据请求的能力需求，智能选择最匹配的数据源适配器。

策略特点：
1. 精确匹配：优先选择完全满足需求的适配器
2. 评分机制：为每个适配器计算匹配分数
3. 多维度考量：考虑数据能力、市场能力、性能、成本等
4. 智能降级：找不到完美匹配时，选择最接近的

使用场景：
- 复杂查询需要特定能力组合
- 需要平衡多个因素（性能、成本、新鲜度）
- 自动化选择最优数据源

作者: RedFire Team
创建日期: 2025-10-06
版本: v1.0
"""

from typing import List, Dict, Optional, Set
import logging

from app.routing.strategy import (
    RoutingStrategy,
    RoutingContext,
    RoutingResult,
    RoutingPriority
)
from app.routing.registry import CapabilityRegistry
from app.adapters.core.capabilities import (
    DataCapability,
    MarketCapability,
    PerformanceLevel,
    DataFreshness
)


class CapabilityBasedRoutingStrategy(RoutingStrategy):
    """
    基于能力的路由策略
    
    根据能力匹配度选择适配器。
    
    评分维度：
    1. 能力匹配度 (40%)
    2. 性能级别 (25%)
    3. 数据新鲜度 (20%)
    4. 可靠性分数 (10%)
    5. 成本级别 (5%)
    
    配置示例：
    ```python
    strategy = CapabilityBasedRoutingStrategy(
        registry=capability_registry,
        min_match_score=0.8,
        performance_weight=0.3
    )
    ```
    """
    
    def __init__(
        self,
        registry: CapabilityRegistry,
        min_match_score: float = 0.5,
        capability_weight: float = 0.4,
        performance_weight: float = 0.25,
        freshness_weight: float = 0.2,
        reliability_weight: float = 0.1,
        cost_weight: float = 0.05,
        logger: Optional[logging.Logger] = None
    ):
        """
        初始化基于能力的路由策略
        
        Args:
            registry: 能力注册表
            min_match_score: 最小匹配分数
            capability_weight: 能力匹配权重
            performance_weight: 性能权重
            freshness_weight: 新鲜度权重
            reliability_weight: 可靠性权重
            cost_weight: 成本权重
            logger: 日志记录器
        """
        super().__init__(
            name="capability_based",
            priority=RoutingPriority.HIGHEST,
            logger=logger
        )
        self.registry = registry
        self.min_match_score = min_match_score
        
        # 权重配置
        self.capability_weight = capability_weight
        self.performance_weight = performance_weight
        self.freshness_weight = freshness_weight
        self.reliability_weight = reliability_weight
        self.cost_weight = cost_weight
        
        # 验证权重总和
        total_weight = sum([
            capability_weight,
            performance_weight,
            freshness_weight,
            reliability_weight,
            cost_weight
        ])
        
        if abs(total_weight - 1.0) > 0.01:
            self.logger.warning(f"权重总和不为1: {total_weight}, 将自动归一化")
            self._normalize_weights(total_weight)
        
        self.logger.info(
            f"基于能力的路由策略初始化: "
            f"最小匹配分数={min_match_score}, "
            f"权重配置=能力{capability_weight}/性能{performance_weight}/"
            f"新鲜度{freshness_weight}/可靠性{reliability_weight}/成本{cost_weight}"
        )
    
    def _normalize_weights(self, total: float):
        """归一化权重"""
        self.capability_weight /= total
        self.performance_weight /= total
        self.freshness_weight /= total
        self.reliability_weight /= total
        self.cost_weight /= total
    
    async def select_adapter(
        self,
        context: RoutingContext,
        available_adapters: List[str]
    ) -> RoutingResult:
        """
        基于能力匹配选择适配器
        
        Args:
            context: 路由上下文
            available_adapters: 可用的适配器列表
        
        Returns:
            RoutingResult: 路由结果
        """
        if not available_adapters:
            return RoutingResult(
                routing_reason="没有可用的适配器",
                confidence_score=0.0
            )
        
        # 从上下文提取能力需求
        required_data_caps = self._extract_data_capabilities(context)
        required_market_caps = self._extract_market_capabilities(context)
        
        # 过滤排除的数据源
        filtered_adapters = [
            adapter for adapter in available_adapters
            if not context.is_provider_excluded(adapter)
        ]
        
        if not filtered_adapters:
            return RoutingResult(
                routing_reason="所有适配器都被排除",
                confidence_score=0.0
            )
        
        # 计算每个适配器的综合评分
        scored_adapters = []
        for adapter_name in filtered_adapters:
            score = self._calculate_adapter_score(
                adapter_name,
                required_data_caps,
                required_market_caps,
                context
            )
            if score >= self.min_match_score:
                scored_adapters.append((adapter_name, score))
        
        if not scored_adapters:
            # 降级：选择评分最高的，即使低于阈值
            all_scores = [
                (adapter_name, self._calculate_adapter_score(
                    adapter_name, required_data_caps, required_market_caps, context
                ))
                for adapter_name in filtered_adapters
            ]
            scored_adapters = sorted(all_scores, key=lambda x: x[1], reverse=True)[:1]
            
            if scored_adapters:
                return RoutingResult(
                    primary_adapter=scored_adapters[0][0],
                    fallback_adapters=[],
                    routing_reason=f"降级选择（评分 {scored_adapters[0][1]:.2f} 低于阈值 {self.min_match_score}）",
                    confidence_score=scored_adapters[0][1]
                )
            else:
                return RoutingResult(
                    routing_reason="没有适配器满足最低要求",
                    confidence_score=0.0
                )
        
        # 按评分排序
        scored_adapters.sort(key=lambda x: x[1], reverse=True)
        
        # 选择主适配器和备选适配器
        primary_adapter = scored_adapters[0][0]
        primary_score = scored_adapters[0][1]
        fallback_adapters = [adapter for adapter, _ in scored_adapters[1:4]]
        
        return RoutingResult(
            primary_adapter=primary_adapter,
            fallback_adapters=fallback_adapters,
            routing_reason=f"能力匹配选择（评分: {primary_score:.2f}）",
            confidence_score=primary_score,
            metadata={
                "all_scores": {adapter: score for adapter, score in scored_adapters},
                "required_data_caps": [cap.value for cap in required_data_caps],
                "required_market_caps": [cap.value for cap in required_market_caps]
            }
        )
    
    def _extract_data_capabilities(self, context: RoutingContext) -> Set[DataCapability]:
        """
        从上下文提取数据能力需求
        
        Args:
            context: 路由上下文
        
        Returns:
            Set[DataCapability]: 数据能力集合
        """
        caps = set()
        
        # 从请求类型推断
        request_type = context.request_type.lower()
        
        if "quote" in request_type or "realtime" in request_type:
            caps.add(DataCapability.REALTIME_QUOTES)
        elif "kline" in request_type or "candlestick" in request_type:
            caps.add(DataCapability.HISTORICAL_KLINE)
        elif "transaction" in request_type or "tick" in request_type:
            caps.add(DataCapability.TICK_DATA)
        elif "fundamental" in request_type or "financial" in request_type:
            caps.add(DataCapability.FUNDAMENTAL_DATA)
        elif "news" in request_type:
            caps.add(DataCapability.NEWS_SENTIMENT)
        
        # 从显式声明的能力添加
        for cap_str in context.required_capabilities:
            try:
                cap = DataCapability(cap_str)
                caps.add(cap)
            except ValueError:
                pass  # 不是数据能力，可能是市场能力
        
        return caps
    
    def _extract_market_capabilities(self, context: RoutingContext) -> Set[MarketCapability]:
        """
        从上下文提取市场能力需求
        
        Args:
            context: 路由上下文
        
        Returns:
            Set[MarketCapability]: 市场能力集合
        """
        caps = set()
        
        # 从证券代码推断市场
        for symbol in context.symbols:
            if not symbol:
                continue
            
            if "." in symbol:
                _, exchange = symbol.split(".", 1)
                exchange = exchange.upper()
                
                if exchange in ("SZ", "SH"):
                    caps.add(MarketCapability.CN_A_SHARES)
                elif exchange == "HK":
                    caps.add(MarketCapability.HK_STOCKS)
                elif exchange == "US":
                    caps.add(MarketCapability.US_STOCKS)
            else:
                # 尝试根据代码格式推断
                if len(symbol) == 6 and symbol.isdigit():
                    caps.add(MarketCapability.CN_A_SHARES)
                elif len(symbol) == 5 and symbol.isdigit():
                    caps.add(MarketCapability.HK_STOCKS)
                elif symbol.isalpha():
                    caps.add(MarketCapability.US_STOCKS)
        
        # 从显式声明的能力添加
        for cap_str in context.required_capabilities:
            try:
                cap = MarketCapability(cap_str)
                caps.add(cap)
            except ValueError:
                pass  # 不是市场能力
        
        return caps
    
    def _calculate_adapter_score(
        self,
        adapter_name: str,
        required_data_caps: Set[DataCapability],
        required_market_caps: Set[MarketCapability],
        context: RoutingContext
    ) -> float:
        """
        计算适配器综合评分
        
        Args:
            adapter_name: 适配器名称
            required_data_caps: 需要的数据能力
            required_market_caps: 需要的市场能力
            context: 路由上下文
        
        Returns:
            float: 综合评分 (0-1)
        """
        info = self.registry.get_adapter_info(adapter_name)
        if not info:
            return 0.0
        
        # 1. 能力匹配分数
        capability_score = info.calculate_match_score(
            required_data_caps,
            required_market_caps
        )
        
        # 2. 性能分数
        performance_score = self._score_performance_level(info.performance_level)
        
        # 3. 新鲜度分数
        freshness_score = self._score_data_freshness(info.data_freshness)
        
        # 4. 可靠性分数
        reliability_score = info.reliability_score
        
        # 5. 成本分数（成本越低越好）
        cost_score = 1.0 - (info.cost_level / 5.0)
        
        # 加权求和
        total_score = (
            capability_score * self.capability_weight +
            performance_score * self.performance_weight +
            freshness_score * self.freshness_weight +
            reliability_score * self.reliability_weight +
            cost_score * self.cost_weight
        )
        
        # 如果在优先列表中，给予额外加分
        if context.is_provider_preferred(adapter_name):
            total_score = min(1.0, total_score * 1.1)
        
        return total_score
    
    def _score_performance_level(self, level: PerformanceLevel) -> float:
        """
        性能级别评分
        
        Args:
            level: 性能级别
        
        Returns:
            float: 评分 (0-1)
        """
        score_map = {
            PerformanceLevel.VERY_HIGH: 1.0,
            PerformanceLevel.HIGH: 0.8,
            PerformanceLevel.MEDIUM: 0.6,
            PerformanceLevel.LOW: 0.4,
            PerformanceLevel.VERY_LOW: 0.2,
        }
        return score_map.get(level, 0.5)
    
    def _score_data_freshness(self, freshness: DataFreshness) -> float:
        """
        数据新鲜度评分
        
        Args:
            freshness: 数据新鲜度
        
        Returns:
            float: 评分 (0-1)
        """
        score_map = {
            DataFreshness.REALTIME: 1.0,
            DataFreshness.NEAR_REALTIME: 0.9,
            DataFreshness.DELAYED: 0.6,
            DataFreshness.END_OF_DAY: 0.4,
            DataFreshness.HISTORICAL: 0.3,
        }
        return score_map.get(freshness, 0.5)
    
    def update_weights(
        self,
        capability: Optional[float] = None,
        performance: Optional[float] = None,
        freshness: Optional[float] = None,
        reliability: Optional[float] = None,
        cost: Optional[float] = None
    ):
        """
        更新权重配置
        
        Args:
            capability: 能力权重
            performance: 性能权重
            freshness: 新鲜度权重
            reliability: 可靠性权重
            cost: 成本权重
        """
        if capability is not None:
            self.capability_weight = capability
        if performance is not None:
            self.performance_weight = performance
        if freshness is not None:
            self.freshness_weight = freshness
        if reliability is not None:
            self.reliability_weight = reliability
        if cost is not None:
            self.cost_weight = cost
        
        # 归一化
        total = sum([
            self.capability_weight,
            self.performance_weight,
            self.freshness_weight,
            self.reliability_weight,
            self.cost_weight
        ])
        self._normalize_weights(total)
        
        self.logger.info("权重已更新并归一化")
    
    def __repr__(self) -> str:
        return (
            f"<CapabilityBasedRoutingStrategy("
            f"min_score={self.min_match_score}, "
            f"weights=C{self.capability_weight:.2f}/P{self.performance_weight:.2f}/"
            f"F{self.freshness_weight:.2f}/R{self.reliability_weight:.2f}/"
            f"Co{self.cost_weight:.2f}"
            f")>"
        )

